package ru.ifmo.croak.sample;

import ru.ifmo.croak.api.Message;
import ru.ifmo.croak.api.MessageListener;
import ru.ifmo.croak.api.MessageQuery;
import ru.ifmo.croak.api.QueryRequest;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.*;

/**
 * Sample implementation of {@link MessageQuery} that provides some random messages.
 *
 * @author Roman Elizarov
 */
public class MessageQueryImpl implements MessageQuery, Runnable {
    private static final long DELAY = 1000;
    private static final ScheduledExecutorService SCHEDULER = Executors.newSingleThreadScheduledExecutor();

    String tag;
    private final QueryRequest request;
    private final List<Message> messages = new ArrayList<Message>();

    private ScheduledFuture<?> scheduled;

    private volatile MessageListener listener;

    public MessageQueryImpl(QueryRequest request, String tag) {
        this.tag = tag;
        this.request = request.clone();
    }

    synchronized void start() {
        scheduled = SCHEDULER.scheduleWithFixedDelay(this, DELAY, DELAY, TimeUnit.MILLISECONDS);
    }

    public QueryRequest getRequest() {
        return request.clone();
    }

    public synchronized List<Message> getMessages() {
        return new ArrayList<Message>(messages);
    }

    public synchronized void close() {
        scheduled.cancel(false);
    }

    public void setMessageListener(MessageListener listener) {
        this.listener = listener;
        for (Message message : getMessages()) {
            notifyListener(message);
        }
    }

    public void run() {
        notifyListener(createMessage());
    }

    private synchronized Message createMessage() {
        Message message = new Message();
        message.setAuthor(tag);
        message.setId(UUID.randomUUID());
        message.setTime(System.currentTimeMillis());
        message.setText("Sample text");
        messages.add(message);
        while (messages.size() > request.getLimit())
            messages.remove(0);
        return message;
    }

    private void notifyListener(Message message) {
        MessageListener listener = this.listener;
        if (listener != null)
            listener.messageAvailable(message);
    }
}
